-
Notifications
You must be signed in to change notification settings - Fork 437
fix: mouse accidentally sticks and drag the node #7186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: mouse accidentally sticks and drag the node #7186
Conversation
📝 WalkthroughWalkthroughAdds local drag-state tracking and safe wrapper functions in the Vue composable to reliably start and end node dragging. Replaces direct calls to startDrag/endDrag with safeDragStart/safeDragEnd and updates pointer event handlers to coordinate drag lifecycle and selection logic. Changes
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/09/2025, 02:47:18 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results❌ Some tests failed ⏰ Completed at: 12/09/2025, 02:56:24 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.21 MB (baseline 3.21 MB) • ⚪ 0 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 979 kB (baseline 978 kB) • 🔴 +318 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 177 kB (baseline 177 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 3.18 kB (baseline 3.18 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 BBundles that do not match a named category
Status: 17 added / 17 removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (1)
84-93: Critical: MissingstartDragcall after setting drag flag.This code path sets
isDraggingVueNodes.value = truewhen the pointer moves beyond the threshold but never callsstartDrag(orsafeDragStart). This means the drag flag is set but the drag operation is never actually initiated, which could be the root cause of the stuck-dragging behavior.Additionally, this is inconsistent with line 80 which correctly uses
safeDragStart.Apply this diff to properly initiate the drag operation:
if (distance > DRAG_THRESHOLD) { - layoutStore.isDraggingVueNodes.value = true handleNodeSelect(event, nodeId) + safeDragStart(event, nodeId) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/composables/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables in the format
useXyz.ts
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
🧬 Code graph analysis (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (1)
src/renderer/core/layout/store/layoutStore.ts (1)
layoutStore(1469-1469)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: test
- GitHub Check: lint-and-format
🔇 Additional comments (3)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (3)
60-60: Good refactoring, but depends on fixingsafeDragStart.Replacing the direct
startDragcall withsafeDragStartis the right approach for consistent error handling. However, this depends on fixing the logic issue insafeDragStart(lines 104-110) where the flag is set in the finally block.
80-80: Good use of safe wrapper for consistency.Using
safeDragStarthere maintains consistency with the drag initiation pattern. Once the logic issue insafeDragStartis fixed, this will correctly handle the multi-select drag case.
133-135: Correctly allows selection logic to execute after drag ends.The removal of the early return after
safeDragEnd(as mentioned in the AI summary) correctly allows the subsequent selection handling logic (lines 140-145) to execute. This ensures that pointer-up events properly handle both drag completion and selection toggling.
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
Show resolved
Hide resolved
Myestery
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of core drag behaviours are broken here
eg Drag and select at once, selecting one item and holding shift and dragging should drag both items
) ## Summary Fixes an issue where Playwright HTML reports were not being generated for `chromium-2x`, `chromium-0.5x`, and `mobile-chrome` test runs, causing 404 errors when accessing report links in PR comments. ## Problem Only the first report link (chromium) had contents - the other three browsers returned 404 errors. Investigation revealed that artifacts for non-chromium browsers were only uploading 1 file (report.json) instead of the full HTML report with ~32 files. The root cause was that these browsers run very few tests (1-6 tests each), and when using `--reporter=html --reporter=json` together, Playwright would only generate the JSON report without the HTML assets. ## Solution Changed the workflow for non-chromium browsers to use the same approach as the sharded chromium tests: 1. Run tests with `--reporter=blob` 2. Generate HTML and JSON reports separately using `merge-reports` This ensures both HTML and JSON reports are always generated with complete assets, regardless of test count. ## Testing The fix can be verified by: 1. Checking that this PR's workflow run uploads similar file counts for all browsers 2. Confirming all 4 report links are accessible and show proper HTML content Related to #7186 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7193-bugfix-Fix-E2E-test-report-generation-for-non-chromium-browsers-2c06d73d365081ba8ea3ed0d3f5d8d38) by [Unito](https://www.unito.io) Co-authored-by: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (1)
29-30: AlignhasDraggingStartedwith successful drag start and shared cleanup
hasDraggingStartedis set in afinallyblock insafeDragStart, so it becomestrueeven ifstartDragthrows. It’s then only reset insidesafeDragEnd, not whencleanupDragStateis called directly (e.g. fromonContextmenuoronScopeDispose). That makes the flag less precise (it doesn’t strictly mean “drag successfully started”) and can leave it out of sync withisDraggingVueNodes.To keep state coherent and follow the error-handling guideline, I’d suggest:
- Only setting
hasDraggingStartedafter a successfulstartDragcall.- Resetting
hasDraggingStartedin the same central cleanup that clearsisDraggingVueNodesso all cancel/end paths behave consistently.- Logging and cleaning up on
startDragerrors, similar tosafeDragEnd.Concrete refactor:
- function cleanupDragState() { - layoutStore.isDraggingVueNodes.value = false - } + function cleanupDragState() { + layoutStore.isDraggingVueNodes.value = false + hasDraggingStarted = false + } @@ - function safeDragStart(event: PointerEvent, nodeId: string) { - try { - startDrag(event, nodeId) - } finally { - hasDraggingStarted = true - } - } + function safeDragStart(event: PointerEvent, nodeId: string) { + try { + startDrag(event, nodeId) + hasDraggingStarted = true + } catch (error) { + console.error('Error during startDrag:', error) + cleanupDragState() + } + } @@ function safeDragEnd(event: PointerEvent) { try { const nodeId = toValue(nodeIdRef) endDrag(event, nodeId) } catch (error) { console.error('Error during endDrag:', error) } finally { - hasDraggingStarted = false cleanupDragState() } }This keeps the flag meaning “we have an active drag” and ensures all end/cancel paths reset both flags together. This is conceptually similar to the earlier review about not setting the drag flag in a
finallyblock, just with a local flag now.As per coding guidelines, this also improves explicit error handling around
startDrag. Please sanity‑check interaction flows (normal drag, cancelled drag via context menu, scope disposal) after this change with tests or manual QA.Also applies to: 102-105, 106-112, 114-124
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively; no new JavaScript code
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,vue}: Use camelCase for variable and function names
Indent with 2 spaces (see.prettierrc)
Use single quotes for strings (see.prettierrc)
No trailing semicolons (see.prettierrc)
Maximum line width of 80 characters (see.prettierrc)
Sort and group imports by plugin (runpnpm formatbefore committing)
Never useanytype; use proper TypeScript types instead
Never useas anytype assertions; fix the underlying type issue instead
Avoid code comments unless absolutely necessary; write expressive, self-documenting code instead
When writing new code, ask if there is a simpler way to introduce the same functionality; if yes, choose the simpler approach
Use refactoring to make complex code simpler
Use es-toolkit for utility functions
Use Vite for fast development and building
Implement proper error handling
Write tests for all changes, especially bug fixes to catch future regressions
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/composables/**/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables with
useXyz.tspattern
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (1)
134-142: Pointer‑up condition change looks correct; ensure it’s covered by testsThe updated condition:
const wasDragging = layoutStore.isDraggingVueNodes.value if (hasDraggingStarted || wasDragging) { safeDragEnd(event) if (wasDragging) { return } }nicely distinguishes:
- “Pre‑drag” cases where
startDragran butisDraggingVueNodesnever flipped totrue(we still end the drag but continue on to selection logic).- True drag cases (
wasDragging === true), where you end the drag and skip the click‑selection behavior.This aligns with the PR’s goal of not leaving drag state stuck while preserving click selection, assuming the flags are managed consistently.
Given how subtle these transitions are, please ensure you have regression tests (or at least targeted interaction tests) that cover:
- Click without moving (no visual drag, but
startDragcalled).- Small movement below
DRAG_THRESHOLD.- Normal drag + drop.
- Multi‑select drag + drop.
thanks. I fixed this case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (1)
107-113: Critical: Flag set in finally block will execute even onstartDragfailure.Setting
hasDraggingStarted = truein the finally block means it will be set even ifstartDragthrows an error. This could leave the system thinking dragging has started when the operation never initialized, potentially causing the stuck-dragging state this PR aims to fix.Apply this diff to set the flag only after successful drag start:
function safeDragStart(event: PointerEvent, nodeId: string) { try { startDrag(event, nodeId) + hasDraggingStarted = true + } catch (error) { + console.error('Error during startDrag:', error) + throw error } finally { - hasDraggingStarted = true } }Alternatively, if you need to guarantee cleanup:
function safeDragStart(event: PointerEvent, nodeId: string) { + hasDraggingStarted = true try { startDrag(event, nodeId) + } catch (error) { + console.error('Error during startDrag:', error) + hasDraggingStarted = false + throw error } finally { - hasDraggingStarted = true } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively; no new JavaScript code
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,vue}: Use camelCase for variable and function names
Indent with 2 spaces (see.prettierrc)
Use single quotes for strings (see.prettierrc)
No trailing semicolons (see.prettierrc)
Maximum line width of 80 characters (see.prettierrc)
Sort and group imports by plugin (runpnpm formatbefore committing)
Never useanytype; use proper TypeScript types instead
Never useas anytype assertions; fix the underlying type issue instead
Avoid code comments unless absolutely necessary; write expressive, self-documenting code instead
When writing new code, ask if there is a simpler way to introduce the same functionality; if yes, choose the simpler approach
Use refactoring to make complex code simpler
Use es-toolkit for utility functions
Use Vite for fast development and building
Implement proper error handling
Write tests for all changes, especially bug fixes to catch future regressions
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
**/composables/**/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables with
useXyz.tspattern
Files:
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: collect
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: test
🔇 Additional comments (3)
src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts (3)
137-142: Verify the pointer-up logic works correctly after fixing the doublestartDragissue.The logic correctly handles drag cleanup and selection toggle, using the captured
wasDraggingstate to decide whether to skip selection handling. However, with the current doublestartDragcall issue (line 62),hasDraggingStartedwill betrueeven for simple clicks, which may not align with the intended behavior.Once the double-call issue is resolved, verify that:
- Actual drags end properly and skip selection toggle
- Threshold-checked drags (below threshold) still allow selection toggle
- Multi-select drags behave correctly
115-125: LGTM: Proper error handling and cleanup insafeDragEnd.The wrapper correctly handles errors from
endDragand ensures state cleanup in the finally block, which is appropriate here since we want to reset drag state regardless of success or failure.
29-29: Consider usingreffor consistency with Vue patterns.While this internal flag doesn't require reactivity, using
ref(false)would align with Vue 3 Composition API conventions and the project's learnings about state management.Apply this diff to use
ref:+import { onScopeDispose, ref, toValue } from 'vue' -let hasDraggingStarted = false +const hasDraggingStarted = ref(false)Then update usage throughout:
-hasDraggingStarted = true +hasDraggingStarted.value = true -hasDraggingStarted = false +hasDraggingStarted.value = false -if (hasDraggingStarted || wasDragging) { +if (hasDraggingStarted.value || wasDragging) {⛔ Skipped due to learnings
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-11-24T19:47:02.860Z Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive stateLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition APILearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listenersLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers
| startPosition.value = { x: event.clientX, y: event.clientY } | ||
|
|
||
| startDrag(event, nodeId) | ||
| safeDragStart(event, nodeId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: startDrag called twice with changed selection between calls.
The current flow calls safeDragStart in both onPointerdown (line 62) and onPointermove (line 83), with handleNodeSelect (line 82) potentially modifying the selection between calls. As noted in previous reviews, startDrag reinitializes draggingNodeIds from the current selectedNodeIds each time, meaning the second call captures a different selection than the first.
This breaks the expected behavior where drag state should capture the selection at drag initiation, not mid-operation.
Remove the premature safeDragStart call from onPointerdown. The drag should only be initialized when actual dragging begins (after movement threshold is met or on first multi-select move):
function onPointerdown(event: PointerEvent) {
// ... existing checks ...
startPosition.value = { x: event.clientX, y: event.clientY }
-
- safeDragStart(event, nodeId)
}Then ensure both drag paths in onPointermove call safeDragStart before setting isDraggingVueNodes:
if (lmbDown && multiSelect && !layoutStore.isDraggingVueNodes.value) {
+ safeDragStart(event, nodeId)
layoutStore.isDraggingVueNodes.value = true
handleNodeSelect(event, nodeId)
- safeDragStart(event, nodeId)
return
}
if (lmbDown && !layoutStore.isDraggingVueNodes.value) {
const dx = event.clientX - startPosition.value.x
const dy = event.clientY - startPosition.value.y
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance > DRAG_THRESHOLD) {
+ safeDragStart(event, nodeId)
layoutStore.isDraggingVueNodes.value = true
handleNodeSelect(event, nodeId)
}
}Also applies to: 83-83
🤖 Prompt for AI Agents
In src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts
around lines 62 and 83, the code calls safeDragStart twice (once in
onPointerdown at line 62 and again in onPointermove at line 83), allowing
handleNodeSelect to change selection between calls and causing startDrag to
capture the wrong selection; remove the safeDragStart call from onPointerdown so
drag initialization only happens once when actual dragging begins, and update
onPointermove so both drag-start code paths invoke safeDragStart immediately
before setting isDraggingVueNodes (ensuring safeDragStart runs only at true drag
start and after selection changes are finalized).
|
Looks good, can you confirm the combo widget failing test is not related? |
I can confirm by nature of seeing this fail on other PRs today. |
christian-byrne
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
https://github.com/user-attachments/assets/88b76852-0050-4f16-a371-916af5232517 --------- Co-authored-by: Johnpaul Chiwetelu <[email protected]>
CleanShot.2025-12-05.at.17.42.04.mp4